package handler

import (
	"context"
	"encoding/json"
	"fmt"
	"go_final/mxshop_srvs/goods_srv/global"
	"go_final/mxshop_srvs/goods_srv/model"
	goodspb "go_final/mxshop_srvs/goods_srv/proto/protofile"

	"github.com/olivere/elastic/v7"

	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"gorm.io/gorm"

	"google.golang.org/protobuf/types/known/emptypb"
)

type Server struct{}

func ModelGood2GoodsInfoResponse(good model.Good) *goodspb.GoodsInfoResponse {
	return &goodspb.GoodsInfoResponse{
		Id:              good.ID,
		CategoryId:      good.CategoryID,
		Name:            good.Name,
		GoodsSn:         good.GoodSn,
		ClickNum:        good.ClickNum,
		SoldNum:         good.SoldNum,
		FavNum:          good.FavNum,
		MarketPrice:     good.MarketPrice,
		ShopPrice:       good.ShopPrice,
		GoodsBrief:      good.GoodsBrief,
		ShipFree:        good.ShipFree,
		Images:          good.Images,
		DescImages:      good.DescImages,
		GoodsFrontImage: good.GoodsFrontImage,
		IsNew:           good.IsNew,
		IsHot:           good.IsHot,
		OnSale:          good.OnSale,
		Category: &goodspb.CategoryBriefInfoResponse{
			Id:   good.CategoryID,
			Name: good.Category.Name,
		},
		Brand: &goodspb.BrandInfoResponse{
			Id:   good.BrandID,
			Name: good.Brand.Name,
			Logo: good.Brand.Logo,
		},
	}
}

func (s Server) GoodsList(c context.Context, request *goodspb.GoodsFilterRequest) (*goodspb.GoodsListResponse, error) {
	// 关键词搜索、查询新品、查询热门商品、通过价格区间筛选、通过分类筛选
	rsp := &goodspb.GoodsListResponse{}

	// match bool查询查询
	q := elastic.NewBoolQuery()
	q = q.Must(elastic.NewTermQuery("tag", "wow"))
	q = q.Filter(elastic.NewTermQuery("account", "1"))

	// 生成一个临时的DB, 并且指明查询哪张表
	if request.KeyWords != "" {
		q = q.Must(elastic.NewMultiMatchQuery(request.KeyWords, "name", "goods_brief"))
	}
	if request.IsHot {
		q = q.Filter(elastic.NewTermQuery("is_hot", request.IsHot))
	}
	if request.IsNew {
		q = q.Filter(elastic.NewTermQuery("is_new", request.IsNew))
	}
	if request.PriceMin > 0 {
		q = q.Filter(elastic.NewRangeQuery("shop_price").Gte(request.PriceMin))
	}
	if request.PriceMax > 0 {
		q = q.Filter(elastic.NewRangeQuery("shop_price").Lte(request.PriceMax))
	}
	if request.Brand > 0 {
		q = q.Filter(elastic.NewTermQuery("brand_id", request.Brand))
	}

	// 通过category去查询查询(如果点击了一个2级类目, 那就要先查询这个类目下的三级类目, 然后查询所有三级类目下的商品)
	// 子查询
	categoryIDs := make([]interface{}, 0)
	if request.TopCategory > 0 {
		var category model.Category
		res := global.DB.First(&category, request.TopCategory)
		if res.RowsAffected == 0 {
			return nil, status.Error(codes.NotFound, "商品分类不存在")
		}

		//var categories []model.Category
		subQuery := ""
		if category.Level == 1 {
			// 一级分类
			subQuery = fmt.Sprintf("select id from categories where parent_category_id in ("+
				"select id from categories where parent_category_id=%d)", request.TopCategory)
		} else if category.Level == 2 {
			subQuery = fmt.Sprintf("select id from categories where parent_category_id=%d", request.TopCategory)
		} else if category.Level == 3 {
			subQuery = fmt.Sprintf("select id from categories where id=%d", request.TopCategory)
		}

		// 查询所有的三级分类ID
		type Result struct {
			ID int32 `json:"id"`
		}
		var results []Result
		global.DB.Model(model.Category{}).Raw(subQuery).Scan(&results)
		for _, result := range results {
			categoryIDs = append(categoryIDs, result.ID)
		}

		// 生成terms查询
		q = q.Filter(elastic.NewTermsQuery("category_id", categoryIDs...))
	}

	// 分页处理
	if request.Pages == 0 {
		request.Pages = 1
	}

	switch {
	case request.PagePerNums > 100:
		request.PagePerNums = 100
	case request.PagePerNums <= 0:
		request.PagePerNums = 10
	}

	res, err := global.EsClient.Search().Index(model.EsGoods{}.GetIndexName()).Query(q).From(int(request.Pages) * int(request.PagePerNums)).Size(int(request.PagePerNums)).Do(context.Background())
	if err != nil {
		return nil, err
	}

	goodsIDs := make([]int32, 0)
	rsp.Total = int32(res.Hits.TotalHits.Value)
	for _, value := range res.Hits.Hits {
		goods := model.EsGoods{}
		_ = json.Unmarshal(value.Source, &goods)
		goodsIDs = append(goodsIDs, goods.ID)
		rsp.Data = append(rsp.Data)
	}

	// 查询id在某个数组的值
	var goods []model.Good
	goodsRes := global.DB.Preload("Brand").Preload("Category").Find(&goods, goodsIDs)

	if goodsRes.Error != nil && goodsRes.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, goodsRes.Error.Error())
	}

	for _, good := range goods {
		rsp.Data = append(rsp.Data, ModelGood2GoodsInfoResponse(good))
	}

	return rsp, nil
}

/* 加入elasticsearch之前
func (s Server) GoodsList(c context.Context, request *goodspb.GoodsFilterRequest) (*goodspb.GoodsListResponse, error) {
	// 关键词搜索、查询新品、查询热门商品、通过价格区间筛选、通过分类筛选
	rsp := &goodspb.GoodsListResponse{}

	var goods []model.Good
	// 生成一个临时的DB, 并且指明查询哪张表
	tmpDB := global.DB.Model(&model.Good{})

	if request.KeyWords != "" {
		tmpDB = tmpDB.Where("name LIKE ?", "%"+request.KeyWords+"%")
	}
	if request.IsHot {
		tmpDB = tmpDB.Where("is_hot=true")
	}
	if request.IsNew {
		tmpDB = tmpDB.Where("is_new=true")
	}
	if request.PriceMin > 0 {
		tmpDB = tmpDB.Where("shop_price >= ? ", request.PriceMin)
	}
	if request.PriceMax > 0 {
		tmpDB = tmpDB.Where("shop_price <= ? ", request.PriceMax)
	}
	if request.Brand > 0 {
		tmpDB = tmpDB.Where("brand_id <= ? ", request.Brand)
	}

	// 通过category去查询查询(如果点击了一个2级类目, 那就要先查询这个类目下的三级类目, 然后查询所有三级类目下的商品)
	// 子查询
	if request.TopCategory > 0 {
		var category model.Category
		res := global.DB.First(&category, request.TopCategory)
		if res.RowsAffected == 0 {
			return nil, status.Error(codes.NotFound, "商品分类不存在")
		}

		//var categories []model.Category
		subQuery := ""
		if category.Level == 1 {
			// 一级分类
			subQuery = fmt.Sprintf("select id from categories where parent_category_id in ("+
				"select id from categories where parent_category_id=%d)", request.TopCategory)
		} else if category.Level == 2 {
			subQuery = fmt.Sprintf("select id from categories where parent_category_id=%d", request.TopCategory)
		} else if category.Level == 3 {
			subQuery = fmt.Sprintf("select id from categories where id=%d", request.TopCategory)
		}

		tmpDB = tmpDB.Where(fmt.Sprintf("category_id in (%s)", subQuery))
	}

	// 开始执行sql语句
	// 查询条数
	var count int64
	// 因为tmpDB已经制定了要查询那个表, 所以不需要使用model
	// tmpDB.Model(&model.Good{}).Count(&count)
	tmpDB.Count(&count)
	rsp.Total = int32(count)

	res := tmpDB.Preload("Brand").Preload("Category").Scopes(Paginate(int(request.Pages), int(request.PagePerNums))).Find(&goods)

	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}

	for _, good := range goods {
		rsp.Data = append(rsp.Data, ModelGood2GoodsInfoResponse(good))
	}

	return rsp, nil
}
*/

// BatchGetGoods 批量查询商品的信息
func (s Server) BatchGetGoods(c context.Context, info *goodspb.BatchGoodsIdInfo) (*goodspb.GoodsListResponse, error) {
	var goods []model.Good

	res := global.DB.Where(info.Id).Find(&goods)
	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}

	rsp := &goodspb.GoodsListResponse{}
	rsp.Total = int32(res.RowsAffected)

	for _, good := range goods {
		rsp.Data = append(rsp.Data, ModelGood2GoodsInfoResponse(good))
	}

	return rsp, nil
}

func (s Server) CreateGoods(c context.Context, info *goodspb.CreateGoodsInfo) (*goodspb.GoodsInfoResponse, error) {
	var category model.Category
	res := global.DB.First(&category, info.CategoryId)
	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}
	if res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "分类不存在")
	}

	var brand model.Brand
	res = global.DB.First(&brand, info.BrandId)
	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}
	if res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "品牌不存在")
	}

	good := model.Good{
		CategoryID:      info.CategoryId,
		BrandID:         info.BrandId,
		OnSale:          info.OnSale,
		ShipFree:        info.ShipFree,
		IsNew:           info.IsNew,
		IsHot:           info.IsHot,
		Name:            info.Name,
		GoodSn:          info.GoodsSn,
		MarketPrice:     info.MarketPrice,
		ShopPrice:       info.ShopPrice,
		GoodsBrief:      info.GoodsBrief,
		Images:          info.Images,
		DescImages:      info.DescImages,
		GoodsFrontImage: info.GoodsFrontImage,
	}

	tx := global.DB.Begin()
	res = tx.Create(&good)
	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		// 可能是AfterCreate勾子里面保存数据到elasticsearch的时候出错了, 也会进到这里面来
		fmt.Println("err ===> ", res.Error)
		tx.Rollback()
		return nil, status.Error(codes.Internal, res.Error.Error())
	}
	tx.Commit()

	return &goodspb.GoodsInfoResponse{
		Id: good.ID,
	}, nil
}

func (s Server) DeleteGoods(c context.Context, info *goodspb.DeleteGoodsInfo) (*emptypb.Empty, error) {
	res := global.DB.Delete(&model.Good{}, info.Id)
	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}
	if res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "商品不存在")
	}
	return &emptypb.Empty{}, nil
}

func (s Server) UpdateGoods(c context.Context, info *goodspb.CreateGoodsInfo) (*emptypb.Empty, error) {
	var goods model.Good

	if result := global.DB.First(&goods, info.Id); result.RowsAffected == 0 {
		return nil, status.Errorf(codes.NotFound, "商品不存在")
	}

	var category model.Category
	if result := global.DB.First(&category, info.CategoryId); result.RowsAffected == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "商品分类不存在")
	}

	var brand model.Brand
	if result := global.DB.First(&brand, info.BrandId); result.RowsAffected == 0 {
		return nil, status.Errorf(codes.InvalidArgument, "品牌不存在")
	}

	goods = model.Good{
		CategoryID:      category.ID,
		Category:        category,
		BrandID:         brand.ID,
		Brand:           brand,
		OnSale:          info.OnSale,
		ShipFree:        info.ShipFree,
		IsNew:           info.IsNew,
		IsHot:           info.IsHot,
		Name:            info.Name,
		GoodSn:          info.GoodsSn,
		MarketPrice:     info.MarketPrice,
		ShopPrice:       info.ShopPrice,
		GoodsBrief:      info.GoodsBrief,
		Images:          info.Images,
		DescImages:      info.DescImages,
		GoodsFrontImage: info.GoodsFrontImage,
	}

	res := global.DB.Updates(&goods)
	if res != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}

	return &emptypb.Empty{}, nil
}

func (s Server) GetGoodsDetail(c context.Context, request *goodspb.GoodInfoRequest) (*goodspb.GoodsInfoResponse,
	error) {
	var good model.Good
	res := global.DB.Preload("Category").Preload("Brand").First(&good, request.Id)
	if res.Error != nil && res.Error != gorm.ErrRecordNotFound {
		return nil, status.Error(codes.Internal, res.Error.Error())
	}

	if res.RowsAffected == 0 {
		return nil, status.Error(codes.NotFound, "商品不存在")
	}

	return ModelGood2GoodsInfoResponse(good), nil
}
